/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include "sdb.h"

#define NR_WP 32



static WP wp_pool[NR_WP] = {};
static WP *head = NULL, *free_ = NULL;

void init_wp_pool() {
  int i;
  for (i = 0; i < NR_WP; i ++) {
    wp_pool[i].NO = i;
    wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
  }

  head = NULL;
  free_ = wp_pool;
}

/* TODO: Implement the functionality of watchpoint */


WP* new_wp(char *exp){
  assert(free_ != NULL);  //没有空余时报错
  WP *temp = free_;
	free_ = free_->next;
  temp->next = NULL;

  bool success = false;
	strcpy(temp->expr, exp);
	temp->val = expr(temp->expr, &success);
	assert(success);

  //在head和next中间插入最新的点
  if(head==NULL)
		head = temp;
	else{
		temp->next = head->next;
    head->next = temp;
	}

	return temp;
}

void free_wp(WP *wp){
	if(wp == NULL)
	    printf("Empty point!\n");
	if(wp == head)
	    head = head -> next;
	else{
	   	WP *p = head;
	   	while(p->next!=wp)
	   		p = p->next;
	   	if(p == NULL)
	   	    return ;
	   	p -> next = wp -> next;
	}
	wp -> next = free_;
	free_ = wp;
	return ;
}

//写监视点命令sdb
void cmd_watch(char *args) {
	WP *wp = new_wp(args);
	printf("Watchpoint %d:%s is set successfully\n",wp->NO,wp->expr);
}

//删除监视点命令sdb
void cmd_delete(char *args) {
	char *arg = strtok(NULL," ");
	int num=0;  //要删除的序号
  sscanf(arg,"%d",&num);
  
  WP *p = head;
  for(int i=0;i<num;i++)
  {
  	p=p->next;
  }
  
	free_wp(p);
		
}

//打印监视点
void print_wp(){
    WP *p = head;
    if(p ==NULL){
        printf("监视点为空！\n");
        return;
    }
    else{
        while(p!=NULL){
            printf("NO:%d   expr:%s   val:%08x\n",p->NO , p->expr, p->val);
            p=p->next;
        }
        return;
    }
    return;
}

//监视点变化 无变化返回0 有变化返回1
int test_change(void){
	WP *p = NULL;
  p = head;
	bool success = false;
  word_t new_val;
	while(p!=NULL){
    new_val = expr(p->expr, &success);
		if (new_val != p->val && success){
      printf("WatchPoint(NO.%d): %s changed, old value:%d, new value:%d \n", p->NO, p->expr,p->val, new_val);
			return 1;
    }
	  else
	  	p=p->next;
  }
  return 0;
}